package com.bjb.vr.client.task;

import cn.hutool.core.lang.UUID;
import cn.hutool.crypto.digest.HMac;
import cn.hutool.crypto.digest.HmacAlgorithm;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.bjb.vr.client.properties.ServerInfoProperties;
import com.bjb.vr.common.constant.*;
import com.bjb.vr.common.dto.SysUpgrade;
import com.bjb.vr.common.exception.CommonException;
import com.bjb.vr.common.mapper.SysUpgradeMapper;
import com.bjb.vr.common.utils.DateTimeUtil;
import com.bjb.vr.common.utils.OkHttpUtil;
import com.bjb.vr.common.utils.ThreadLocalUtil;
import com.bjb.vr.common.utils.XrVersionUtil;
import com.bjb.vr.common.vo.UmsAccountVo;
import lombok.extern.slf4j.Slf4j;
import okhttp3.Call;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpStatus;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.*;

/**
 * @description:
 * @author: hujingbo
 * @create: 2022-07-28 10:54
 **/
@Slf4j
@Component
public class SyncUpgradeTask {

    @Resource
    private ServerInfoProperties serverInfoProperties;

    @Resource
    private SysUpgradeMapper upgradeMapper;

    /**
     * 每隔10秒查询，需要升级的数据库数据，如果存在最新的需要升级的数据，则执行升级任务
     * 【云服务不需要此操作】
     */
    @Async
    @Scheduled(fixedDelay = 1000 * 10, initialDelay = 5000)
    public void handleUpgradeTask() {
        // 如果是云端服务，直接跳过
        if (ServerModeConstant.LOCAL.equals(serverInfoProperties.getDeployMode())) {
            // 根据配置文件变化，动态执行任务
            if (serverInfoProperties.getNeedUpgrade()) {
                // 执行服务升级任务操作
                executeUpgrade();
            }
        }
    }

    /**
     * 执行服务升级任务操作
     */
    private void executeUpgrade() {
        // 检查参数
        String tenantId = serverInfoProperties.getTenantId();
        if (StringUtils.isBlank(tenantId) && ServerModeConstant.LOCAL.equals(serverInfoProperties.getDeployMode())) {
            log.error("当前服务类型为: {} 并且没有指定租户ID，所以数据不进行同步...", ServerModeConstant.LOCAL);
            throw new CommonException("租户ID为空,不能进行服务升级操作...");
        }

        // 1、获取请求数据
        String requestId = UUID.fastUUID().toString();
        String requestTime = DateTimeUtil.nowStrTime();
        StringBuilder builder = new StringBuilder();
        String data = builder.append(tenantId).append(requestId).append(requestTime).toString();
        byte[] key = EncryptConstant.ENCRYPT_KEY.getBytes();
        HMac mac = new HMac(HmacAlgorithm.HmacMD5, key);
        String signature = mac.digestHex(data);

        // 2、封装请求数据
        String upgradeInfoUrl = serverInfoProperties.getUpgradeInfoUrl();
        HashMap<String, String> params = new HashMap<>();
        params.put("tenantId", tenantId);
        params.put("requestId", requestId);
        params.put("requestTime", requestTime);
        params.put("signature", signature);

        // 3、发送请求
        OkHttpUtil httpUtil = OkHttpUtil.builder().url(upgradeInfoUrl).addHeader("Content-Type", "application/json; charset=utf-8");
        Iterator<Map.Entry<String, String>> iterator = params.entrySet().iterator();
        while (iterator.hasNext()) {
            Map.Entry<String, String> next = iterator.next();
            httpUtil.addParam(next.getKey(), next.getValue());
        }

        httpUtil.post(true).async(new OkHttpUtil.ICallBack() {
            @Override
            public void onSuccessful(Call call, String data) {
                JSONObject object = JSONObject.parseObject(data);
                if (object.containsKey(SyncDataConstant.STATUS) && HttpStatus.SC_NOT_FOUND == (Integer) object.get(SyncDataConstant.STATUS)) {
                    log.error("从云端服务器获取数据失败！| 原因: {}", object.get(SyncDataConstant.ERROR));
                    return;
                }
                if (object.containsKey(SyncDataConstant.CODE) && String.valueOf(HttpStatus.SC_INTERNAL_SERVER_ERROR).equals(object.get(SyncDataConstant.CODE))) {
                    log.error("从云端服务器获取数据失败！| 原因: {}", object.get(SyncDataConstant.MESSAGE));
                    return;
                }
                if (object.containsKey(SyncDataConstant.CODE) && String.valueOf(HttpStatus.SC_UNAUTHORIZED).equals(object.get(SyncDataConstant.CODE))) {
                    log.error("从云端服务器获取数据失败！| 原因: {}", object.get(SyncDataConstant.MESSAGE));
                    return;
                }

                // 获取数据成功
                JSONArray dataArray = (JSONArray) object.get(SyncDataConstant.DATA);
                if (dataArray.size() > 0) {
                    log.debug("从云端服务器获取[{}]条【升级数据】", dataArray.size());
                    saveStatement(dataArray);
                }
            }

            @Override
            public void onFailure(Call call, String errorMsg) {
                log.error("请检查网络连通情况...... {}", errorMsg);
            }
        });
    }

    /**
     * 更新最新的升级数据
     *
     * @param dataArray
     */
    private void saveStatement(JSONArray dataArray) {
        try {
            List<SysUpgrade> zipList = new ArrayList<>();
            List<SysUpgrade> apkList = new ArrayList<>();
            for (int i = 0; i < dataArray.size(); i++) {
                JSONObject object = dataArray.getJSONObject(i);
                SysUpgrade upgrade = JSONObject.parseObject(object.toJSONString(), SysUpgrade.class);
                if (upgrade.getPackageType().equals(UpgradeConstants.ZIP)) {
                    zipList.add(upgrade);
                } else {
                    apkList.add(upgrade);
                }
            }
            // 处理zip包信息
            handleZipData(zipList);
            // 处理apk包信息
            handleApkData(apkList);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 处理APK包升级数据
     *
     * @param apkList
     */
    private void handleApkData(List<SysUpgrade> apkList) {
        try {
            String tenantId = serverInfoProperties.getTenantId();
            for (SysUpgrade sysUpgrade : apkList) {
                ThreadLocalUtil.set(ThreadLocalConstant.NO_TENANT_ID_VERIFY, true);
                UmsAccountVo umsAccountVo = new UmsAccountVo();
                umsAccountVo.setTenantId(tenantId);
                ThreadLocalUtil.set(ThreadLocalConstant.USER_ACCOUNT_INFO, umsAccountVo);
                // 查询数据库中最新版本
                Integer exist = upgradeMapper.existVersion(sysUpgrade.getVersion(), sysUpgrade.getPackageType(), tenantId);
                if (exist != null) {
                    log.debug("当前APK包数据不是最新,无须同步...[版本号相同]");
                    continue;
                }
                // 校验为发布版本号是否大于已发布版本号
                String latestVersion = upgradeMapper.queryLatestVersion(sysUpgrade.getPackageType(), tenantId);
                if (StringUtils.isNotBlank(latestVersion)) {
                    boolean greater = XrVersionUtil.isGreaterVersion(latestVersion, sysUpgrade.getVersion());
                    if (!greater) {
                        log.debug("当前APK包数据不是最新,无须同步...[版本号小于数据库最大版本]");
                        continue;
                    }
                }
                upgradeMapper.insert(sysUpgrade);
                log.info("同步APK包升级数据成功...");
            }
        } catch (Exception e) {
            log.error(e.getMessage());
        }
    }

    /**
     * 处理ZIP包升级数据
     *
     * @param zipList
     */
    public void handleZipData(List<SysUpgrade> zipList) {
        try {
            String tenantId = serverInfoProperties.getTenantId();
            for (SysUpgrade sysUpgrade : zipList) {
                ThreadLocalUtil.set(ThreadLocalConstant.NO_TENANT_ID_VERIFY, true);
                UmsAccountVo umsAccountVo = new UmsAccountVo();
                umsAccountVo.setTenantId(tenantId);
                ThreadLocalUtil.set(ThreadLocalConstant.USER_ACCOUNT_INFO, umsAccountVo);
                // 查询数据库中最新版本
                Integer exist = upgradeMapper.existVersion(sysUpgrade.getVersion(), sysUpgrade.getPackageType(), tenantId);
                if (exist != null) {
                    log.debug("当前ZIP包数据不是最新,无须同步...[版本号相同]");
                    return;
                }
                // 校验为发布版本号是否大于已发布版本号
                String latestVersion = upgradeMapper.queryLatestVersion(sysUpgrade.getPackageType(), tenantId);
                if (StringUtils.isNotBlank(latestVersion)) {
                    boolean greater = XrVersionUtil.isGreaterVersion(latestVersion, sysUpgrade.getVersion());
                    if (!greater) {
                        log.debug("当前ZIP包数据不是最新,无须同步...[版本号小于数据库最大版本相同]");
                        return;
                    }
                }
                upgradeMapper.insert(sysUpgrade);
                log.info("同步ZIP包升级数据成功...");
            }
        } catch (Exception e) {
            log.error(e.getMessage());
        }
    }
}
